﻿#include "common.h"

#ifdef WIN32
#include <WinSock2.h>
#include <Iphlpapi.h>
#else
#include <string.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#endif


void dump_payload(void* _p, int len)
{
    char buf[128];
    int i, j, i0;
    const unsigned char* p = (const unsigned char*)_p;

    /* get the length in ASCII of the length of the packet. */

    printf("cur data len : %d \n", len);
    /* hexdump routine */
    for (i = 0; i < len; ) {
        memset(buf, ' ', sizeof(buf));
        sprintf(buf, "%5d: ", i);
        i0 = i;
        for (j = 0; j < 16 && i < len; i++, j++)
            sprintf(buf + 7 + j * 3, "%02x ", (uint8_t)(p[i]));
        i = i0;
        for (j = 0; j < 16 && i < len; i++, j++)
            sprintf(buf + 7 + j + 48, "%c",
                isprint(p[i]) ? p[i] : '.');
        printf("%s\n", buf);
    }
}

int GetIfname(char* name, char* p)
{
    while (isspace(*p))
        p++;
    while (*p) {
        if (isspace(*p))
            break;
        if (*p == ':')
        {
            char* dot = p, * dotname = name;
            *name++ = *p++;
            while (isdigit(*p))
                *name++ = *p++;
            if (*p != ':')
            {
                p = dot;
                name = dotname;
            }
            if (*p == '\0')
                return -1;
            p++;
            break;
        }
        *name++ = *p++;
    }
    *name++ = '\0';
    return 0;
}

uint64_t ntohll(uint64_t val)
{
    if (__BYTE_ORDER == __LITTLE_ENDIAN)
    {
        return (((uint64_t)htonl((int)((val << 32) >> 32))) << 32) | (uint32_t)htonl((int)(val >> 32));
    }
    else if (__BYTE_ORDER == __BIG_ENDIAN)
    {
        return val;
    }
}

uint64_t htonll(uint64_t val)
{
    if (__BYTE_ORDER == __LITTLE_ENDIAN)
    {
        return (((uint64_t)htonl((int)((val << 32) >> 32))) << 32) | (uint32_t)htonl((int)(val >> 32));
    }
    else if (__BYTE_ORDER == __BIG_ENDIAN)
    {
        return val;
    }
}

void NetPackHead::toHost()
{
    m_header.ether_type = ntohs(m_header.ether_type);
    m_task_id = ntohll(m_task_id);
    m_curframe = ntohs(m_curframe);
    m_allframe = ntohs(m_allframe);
    m_data_len = ntohs(m_data_len);
}

void NetPackHead::toNet()
{
    m_header.ether_type = htons(m_header.ether_type);
    m_task_id = htonll(m_task_id);
    m_curframe = htons(m_curframe);
    m_allframe = htons(m_allframe);
    m_data_len = htons(m_data_len);
}

#ifdef WIN32

std::string GetIfByMac(const std::string& macStr)
{
    std::string ifname = "", lowerMac = "";
    int ret = 0, curPos = 0;
    char mac[128] = { 0 };

    PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO[1];
    unsigned long stSize = sizeof(IP_ADAPTER_INFO);

    for (auto& c : macStr) {
        if (c >= 'A' && c <= 'Z')
            lowerMac.push_back(c + 32);
        else
            lowerMac.push_back(c);
    }

    ret = GetAdaptersInfo(pIpAdapterInfo, &stSize);
    if (ERROR_BUFFER_OVERFLOW == ret)
    {
        delete[] pIpAdapterInfo;

        pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize];
        ret = GetAdaptersInfo(pIpAdapterInfo, &stSize);
    }
    if (ERROR_SUCCESS != ret)
    {
        delete[] pIpAdapterInfo;
        return ifname;
    }

    while (pIpAdapterInfo)
    {
        memset(mac, 0x00, sizeof(mac));

        for (DWORD i = 0, curPos = 0; i < pIpAdapterInfo->AddressLength; i++)
        {
            if (i < pIpAdapterInfo->AddressLength - 1)
            {
                curPos += sprintf(mac + curPos, "%02x:", pIpAdapterInfo->Address[i]);
            }
            else
            {
                sprintf(mac + curPos, "%02x", pIpAdapterInfo->Address[i]);
            }
        }

        if (0 == lowerMac.compare(mac))
        {
            ifname.assign(pIpAdapterInfo->AdapterName);
        }
        pIpAdapterInfo = pIpAdapterInfo->Next;
    }
    return ifname;
}

#else

std::string GetIfByMac(const std::string& macStr)
{
    int fd = -1, interfaceNum = 0;
    struct ifreq ifr;
    char mac[128] = { 0 }, szName[128] = { 0 }, buf[1024] = { 0 };
    std::string ifname = "", lowerMac = "";

    for (auto& c : macStr) {
        if (c >= 'A' && c <= 'Z')
            lowerMac.push_back(c + 32);
        else
            lowerMac.push_back(c);
    }

    if ((fd = socket(PF_PACKET, SOCK_RAW, 0)) < 0)
    {
        close(fd);
        return ifname;
    }

    FILE* fp = fopen("/proc/net/dev", "r");
    if (fp == NULL)
    {
        return ifname;
    }

    while (NULL != fgets(buf, sizeof buf, fp))
    {
        memset(szName, 0x00, sizeof(szName));
        GetIfname(szName, buf);

        memset(&ifr, 0, sizeof(struct ifreq));
        strcpy(ifr.ifr_name, szName);


        if (0 != ioctl(fd, SIOCGIFHWADDR, &ifr))
        {
            continue;
        }

        memset(mac, 0x00, sizeof(mac));
        sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x",
            (unsigned char)ifr.ifr_hwaddr.sa_data[0],
            (unsigned char)ifr.ifr_hwaddr.sa_data[1],
            (unsigned char)ifr.ifr_hwaddr.sa_data[2],
            (unsigned char)ifr.ifr_hwaddr.sa_data[3],
            (unsigned char)ifr.ifr_hwaddr.sa_data[4],
            (unsigned char)ifr.ifr_hwaddr.sa_data[5]);
        if (0 == lowerMac.compare(mac))
        {
            ifname.assign(ifr.ifr_name);
            break;
        }
    }
    close(fd);
    return ifname;
}

#endif